/*	Copyright (c) 2010 MIEM (http://miem.edu.ru/)
 *
 *	Authors:
 *		* Andrey Shtykovskiy    ( ashty@itas.miem.edu.ru      )
 *		* Edward Klyshinsky     ( klyshinsky@itas.miem.edu.ru )
 *		* Sergey R. Tumkovsky   ( srt@itas.miem.edu.ru        )
 *
 *	This file is part of MOAN (morphology analysis) software.
 *
 *	MOAN is free software: you can redistribute it and/or modify it 
 *	under the terms of the GNU General Public License as published 
 *	by the Free Software Foundation, either version 3 of the License, 
 *	or (at your option) any later version.
 *
 *	This library is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *	Lesser General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License 
 *	along with MOAN. If not, see http://www.gnu.org/licenses/.
 */

#ifndef __DICTIONARY_TEST_HPP__
#define __DICTIONARY_TEST_HPP__

#include <assert.h>
#include <stddef.h>				//for NULL

#include <vector>

#include "..\..\thirdparty\gtest\gtest.h"

#include "..\..\src\moan\dictionary.hpp"

/*	Fixture for testing basic dictionary functionality.
 */
class dictionary_test : public ::testing::Test {
protected:
	
	typedef int	item_type;
	typedef std::vector<item_type> key_type;
	typedef std::vector<item_type> parameter_collection_type;
	typedef moan::dictionary<item_type, parameter_collection_type> dictionary_type;

	dictionary_test() : dictionary(NULL) { }

	virtual void SetUp() {
		dictionary = new dictionary_type();

		assert(dictionary);

		parameter.clear();
		key.clear();
	}

	virtual void TearDown() {

		assert(dictionary);

		delete dictionary;
		dictionary = NULL;
	}

	dictionary_type *dictionary;
	parameter_collection_type parameter;
	key_type key;
};

TEST_F(dictionary_test, counters_on_create) {
	ASSERT_TRUE( dictionary->empty() );
	ASSERT_EQ( 0, dictionary->size() );
}


TEST_F(dictionary_test, insert) {
	key.push_back(11);
	key.push_back(22);

	parameter.push_back(220);

	dictionary->insert(key.begin(), key.end(), parameter);

	ASSERT_FALSE( dictionary->empty() );
	ASSERT_EQ( 1, dictionary->size() );
}

TEST_F(dictionary_test, search) {
	key.push_back(11);
	key.push_back(22);

	parameter.push_back(220);

	dictionary->insert(key.begin(), key.end(), parameter);

	parameter.clear();

	bool key_found = dictionary->search(key.begin(), key.end(), &parameter);

	ASSERT_TRUE(key_found);
	ASSERT_EQ( 1, parameter.size() );
	ASSERT_EQ( 220, parameter[0] );
}

class dictionary_test_filled : public dictionary_test {
protected:
	virtual void SetUp() {
		dictionary_test::SetUp();

		/* a key with parameter */
		key.push_back(11);
		key.push_back(11);

		parameter.push_back(100);

		dictionary->insert(key.begin(), key.end(), parameter);

		key.clear();
		parameter.clear();

		/* a key that extends a key */
		key.push_back(11);
		key.push_back(11);
		key.push_back(12);
		key.push_back(13);

		parameter.push_back(200);

		dictionary->insert(key.begin(), key.end(), parameter);

		key.clear();
		parameter.clear();

		/* different branch key */
		key.push_back(21);
		key.push_back(22);
		key.push_back(23);
		key.push_back(24);

		parameter.push_back(300);

		dictionary->insert(key.begin(), key.end(), parameter);

		key.clear();
		parameter.clear();

		/* a key with 2 parameters added sequentially */
		key.push_back(21);
		key.push_back(23);

		parameter.push_back(400);

		dictionary->insert(key.begin(), key.end(), parameter);

		parameter.clear();
		parameter.push_back(500);

		dictionary->insert(key.begin(), key.end(), parameter);

		key.clear();
		parameter.clear();
	}

	virtual void TearDown() {
		dictionary_test::TearDown();

		key.clear();
		parameter.clear();
	}
};

TEST_F( dictionary_test_filled, search_key ) {
	key.push_back(11);
	key.push_back(11);

	bool key_found = dictionary->search(key.begin(), key.end(), &parameter);

	ASSERT_TRUE(key_found);
	ASSERT_EQ( 1, parameter.size() );
	ASSERT_EQ( 100, parameter[0] );
}

TEST_F( dictionary_test_filled, search_key_extend ) {
	key.push_back(11);
	key.push_back(11);
	key.push_back(12);
	key.push_back(13);

	bool key_found = dictionary->search(key.begin(), key.end(), &parameter);

	ASSERT_TRUE(key_found);
	ASSERT_EQ( 1, parameter.size() );
	ASSERT_EQ( 200, parameter[0] );
}

TEST_F( dictionary_test_filled, search_key_different_branches ) {
	key.push_back(21);
	key.push_back(22);
	key.push_back(23);
	key.push_back(24);

	bool key_found = dictionary->search(key.begin(), key.end(), &parameter);

	ASSERT_TRUE(key_found);
	ASSERT_EQ( 1, parameter.size() );
	ASSERT_EQ( 300, parameter[0] );
}

TEST_F( dictionary_test_filled, search_key_miltiple_parameters ) {
	key.push_back(21);
	key.push_back(23);

	bool key_found = dictionary->search(key.begin(), key.end(), &parameter);

	ASSERT_TRUE(key_found);
	ASSERT_EQ( 2, parameter.size() );
	ASSERT_EQ( 400, parameter[0] );
	ASSERT_EQ( 500, parameter[1] );
}



#endif /* __DICTIONARY_TEST_HPP__ */